/**************************************************************************************************
* Title: SumMeshLoader.cpp
* Author: Gael Huber
* Description: Loads 3DS Max .3ds mesh files for use within SumEngine.
**************************************************************************************************/
#include "SumMeshLoader.h"

/**************************************************************************************************
* Initialize the singleton instance of this class to 0
**************************************************************************************************/
template <> MeshLoader* Singleton<MeshLoader>::singleton = 0;

/**************************************************************************************************
* Constructor
**************************************************************************************************/
MeshLoader::MeshLoader(void) 
{ }

/**************************************************************************************************
* Destructor
**************************************************************************************************/
MeshLoader::~MeshLoader(void) 
{ }

struct L{
	unsigned char a[25555];
};

/**************************************************************************************************
* Load a mesh from file
**************************************************************************************************/
void MeshLoader::load(String filepath) { 
	// First thing to do is to open the file
	FILE* file = 0;
	fopen_s(&file, filepath.c_str(), "r");

	// Read chunks from the file while the file is valid
	while(readChunk(file)) {


	}

	// Close the file
	fclose(file);
}

/**************************************************************************************************
* Read a chunk of data from the file
**************************************************************************************************/
int MeshLoader::readChunk(FILE* file) {
	// See if we can successfully initiate read
	if(readUINT(file) == 0x4D4D) {		
		// Relocated to chunk start
		fseek(file, 16, SEEK_SET);

		// Read the file
		unsigned int id;
		unsigned long len;
		int done = 0;
		while(!done) {
			// Get the chunk ID and length
			id = readUINT(file);
			len = readULONG(file);

			// Check end of file
			if(feof(file)) {
				done = 1;
				break;
			}

			// Parse ID
			switch(id) {
			// Done
			case 0xFFFF:
				done = 1;
				break;

			// Read an object
			case 0x3D3D:
				readObject(file, len);
				break;

			default:
				break;
			}
		}
	} else {
		// Failure
		return 0;
	}

	// Success
	return 1;
}

/**************************************************************************************************
* Read the object from the file
**************************************************************************************************/
void MeshLoader::readObject(FILE* file, unsigned long len) {
	unsigned long count = ftell(file) + len - 6;
	unsigned int id;
	unsigned long llen;
	int done = 0;
	while(!done) {
		id = readUINT(file);

		// Check end of file
		if(feof(file)) {
			done = 1;
			break;
		}

		llen = readULONG(file);
		
		//  Parse either mesh or material
		switch(id) {
		// MESH!
		case 0x4000:
			readMesh(file, llen);
			break;

		// MATERIAL!
		case 0xAFFF:
			readMaterial(file, llen);
			break;
		}
	}
}

/**************************************************************************************************
* Read mesh data
**************************************************************************************************/
void MeshLoader::readMesh(FILE* file, unsigned long len) {
	// Mesh to construct
	mesh = new Mesh;

	// Read the mesh name
	int u = 0;
	char ch;
	while((ch = readUCHAR(file)) != 0) {
		mesh->name[u++] = ch;
	}
	mesh->name[u] = '\0';

	// Get current position in array
	unsigned long count = ftell(file) + len - 6;
	unsigned int id;
	unsigned long llen;
	int done = 0;
	while(!done) {
		id = readUINT(file);

		// If end of file, break
		if(feof(file)) {
			done = 1;
			break;
		}

		llen = readULONG(file);

		switch(id) {
		// Read vertex data
		case 0x4110:
			mesh->numVertices = readUINT(file);

			// Create the vertex buffer
			Vertex* vertices;
			vertices = new Vertex[mesh->numVertices];

			// Read in vertices
			unsigned int i;
			for(i = 0; i < mesh->numVertices; ++i) {
				Vector3 v = Vector3(readFLOAT(file), readFLOAT(file), readFLOAT(file));
				vertices[i] = Vertex(
					v,//Vector3(readFLOAT(file), readFLOAT(file), readFLOAT(file)),
					Vector4((v.x > 0) ? 1.0f : 0.0f, (v.y > 0) ? 1.0f : 0.0f, (v.z > 0) ? 1.0f : 0.0f, 1.0f)
					);
				float v2;
				v2 = 0.0f;
			}
				
			// Create the buffer description
			D3D11_BUFFER_DESC bd;
			ZeroMemory(&bd, sizeof(D3D11_BUFFER_DESC));
			bd.Usage = D3D11_USAGE_DEFAULT;
			bd.ByteWidth = sizeof(Vertex) * mesh->numVertices;
			bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
			bd.CPUAccessFlags = 0;
	
			// Create the subresource data
			D3D11_SUBRESOURCE_DATA initData;
			ZeroMemory(&initData, sizeof(D3D11_SUBRESOURCE_DATA));
			initData.pSysMem = vertices;

			// Initialize the vertex buffer
			RenderManager::getSingletonPtr()->createBuffer(&bd, &initData, &RenderManager::getSingletonPtr()->mesh.vertexBuffer);

			break;

		// Face data
		case 0x4120:
			// Read number of faces on the mesh
			mesh->numFaces = readUINT(file);

			// Create a list of faces
			//unsigned short faces[36];
			unsigned short* indices;
			indices = new unsigned short[mesh->numFaces * 3];
			for(i = 0; i < mesh->numFaces; ++i) {
				unsigned short test;
				// Insert counter-clockwise, 3DS files have closed faces, but as we are using triangle strips, 
				// we don't need the "closing" index. Therefore we can just read it but ignore it
				//struct Vect {
				//	unsigned short a;
				//	unsigned short b;
				//	unsigned short c;
				//}v;
				//fread(&v.a, sizeof(unsigned short), 1, file);
				//fread(&v.b, sizeof(unsigned short), 1, file);
				//fread(&v.c, sizeof(unsigned short), 1, file);
				
				fread(&indices[i*3+2], sizeof(unsigned short), 1, file);
				fread(&indices[i*3+1], sizeof(unsigned short), 1, file);
				fread(&indices[i*3+0], sizeof(unsigned short), 1, file);
				fread(&test, sizeof(unsigned short), 1, file);
			}

			// Create the index buffer
			bd.Usage = D3D11_USAGE_DEFAULT;
			bd.ByteWidth = sizeof(unsigned short) * mesh->numFaces * 3;        // 36 vertices needed for 12 triangles in a triangle list
			bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
			bd.CPUAccessFlags = 0;
			initData.pSysMem = indices;

			RenderManager::getSingletonPtr()->createBuffer(&bd, &initData, &RenderManager::getSingletonPtr()->mesh.indexBuffer);

			break;

		// Another object
		case 0x4000:
			fseek(file, -6, SEEK_CUR);
			done = 1;
			break;
		}
	}
}

/**************************************************************************************************
* Read material data from the file
**************************************************************************************************/
void MeshLoader::readMaterial(FILE* file, unsigned long len) {
	// Find our current position in the file data
	unsigned long count = ftell(file) + len - 6;

//	unsigned int id;
//	unsigned long llen;
//	int done = 0;

}